#include "string.h"


s_string* createString() {
	return createStringA( "" );
}

s_string* createStringA( const char* str ) {
	if( !str ) {
		return NULL;
	}
	
	s_string* s = NEW( s_string );
	s_uint i = strlen( str ) + 1;
	
	s->data = NEW_ARRAY( s_ubyte, i );
	strcpy( s->data, str );
	s->size = i;
	s->length = getStringLength( s );
	
	return s;
}

s_string* createStringW( const wchar_t* str ) {
	if( !str ) {
		return NULL;
	}
	
	s_string* s = NEW( s_string );
	s_uint j = 0, i = 0, k = 0;
	s_ushort c = 0;
	
	while( ( c = str[ i++ ] ) ) {
		if( c < 0x80 ) {
			++j;
		} else if( c < 0x800 ) {
			j += 2;
		} else {
			j += 3;
		}
	}

	s->data = NEW_ARRAY( s_ubyte, j );
	s->size = j;
	
	s_ubyte* out = s->data;
	
	i = 0;
	j = 0;
	while( ( c = str[ i++ ] ) ) {
		if( c < 0x80 ) {
			out[ j++ ] = (unsigned char)c;
		} else if( c < 0x800 ) {
			out[ j++ ] = 0xC0 | ( c >> 6 );
			out[ j++ ] = 0x80 | ( c & 0x3F );
		} else {
			out[ j++ ] = 0xE0 | ( c >> 12 );
			out[ j++ ] = 0x80 | ( ( c >> 6 ) & 0x3F );
			out[ j++ ] = 0x80 | ( c & 0x3F );
		}
		++k;
	}
	s->length = k;
		
	return s;
}

s_string* createStringC( const s_char* str ) {
	if( !str ) {
		return NULL;
	}
	
	s_string* s = NEW( s_string );
	s_uint j = 1, i = 0, k = 0;
	s_char c = 0;
	
	while( ( c = str[ i++ ] ) ) {
		if( c < 0x80 ) {
			++j;
		} else if( c < 0x800 ) {
			j += 2;
		} else if( c < 0x10000 ) {
			j += 3;
		} else {
			j += 4;
		}
	}

	s->data = NEW_ARRAY( s_ubyte, j );
	s->size = j;
	
	s_ubyte* out = s->data;
	
	i = 0;
	j = 0;
	while( ( c = str[ i++ ] ) ) {
		if( c < 0x80 ) {
			out[ j++ ] = (unsigned char)c;
		} else if( c < 0x800 ) {
			out[ j++ ] = 0xC0 | ( c >> 6 );
			out[ j++ ] = 0x80 | ( c & 0x3F );
		} else if( c < 0x10000 ) {
			out[ j++ ] = 0xE0 | ( c >> 12 );
			out[ j++ ] = 0x80 | ( ( c >> 6 ) & 0x3F );
			out[ j++ ] = 0x80 | ( c & 0x3F );
		} else {
			out[ j++ ] = 0xF0 | ( ( c >> 18 ) );
			out[ j++ ] = 0x80 | ( ( c >> 12 ) & 0x3F );
			out[ j++ ] = 0x80 | ( ( c >> 6 ) & 0x3F );
			out[ j++ ] = 0x80 | ( c & 0x3F );
		}
		++k;
	}
	s->length = k;
		
	return s;
}

s_string* createStringCopy( const s_string* str ) {
	s_string* s = NEW( s_string );
	strcpy( s->data, str->data );
	s->length = str->length;
	s->size = str->size;
	
	return s;
}

void deleteString( s_string* str ) {
	SAFE_DELETE( str->data );
	SAFE_DELETE( str );
}

s_uint getStringLengthInBytes( const s_string* str ) {
	return str->size;
}

s_uint getStringLength( const s_string* str ) {
	/*s_uint length = 0, i = 0;
	s_ubyte code;
	s_ubyte* utf = str->data;
	
	while( ( code = utf[ i ] ) ) {
		i += utf8Skip( code );
		++length;
	}
	
	return length;*/
	return str->length;
}

s_string_compare compareString( const s_string* str1, const s_string* str2 ) {
	return strcmp( str1->data, str2->data );
}

s_string_compare compareStringIgnoreCase( const s_string* str1, const s_string* str2 ) {
	return strcasecmp( str1->data, str2->data );
}

s_string_compare compareStringCharacters( const s_string* str, s_uint start, s_uint end ) {
	return 0;
}

s_string_compare compareStringCharactersIgnoreCase( const s_string* str, s_uint count ) {
	return 0;
}

s_boolean isStringEqual( const s_string* str1, const s_string* str2 ) {
	return s_false;
}

s_boolean isStringEqualIgnoreCase( const s_string* str1, const s_string* str2 ) {
	return s_false;
}

s_boolean isStringEmpty( const s_string str ) {
	return s_false;
}

s_char charAt( const s_string* str, s_uint at ) {
	if( !str ) {
		return -1;
	}
	if( at > str->length ) {
		return -1;
	}
	
	s_uint length = 0, i = 0, j = 0;
	s_ubyte code;
	s_ubyte* utf = str->data;
	s_char ch = 0;
	
	while( ( code = utf[ i ] ) ) {
		if( length == at ) {
			j = i;
			if( ( code >> 5 ) == 0x6 ) {
				ch =  0xC0 | ( utf[ j ] >> 6 );
				ch &= 0x80 | ( utf[ j++ ] & 0x3F );
			} else if( ( code >> 4 ) == 0xE ) {
				ch =  0xE0 | ( utf[ j ] >> 12 );
				ch &= 0x80 | ( ( utf[ j++ ] >> 6 ) & 0x3F );
				ch &= 0x80 | ( utf[ j++ ] & 0x3F );
			} else if( ( code >> 3 ) == 0x1E ) {
				ch =  0xF0 | ( ( utf[ j ] >> 18 ) );
				ch &= 0x80 | ( ( utf[ j++ ] >> 12 ) & 0x3F );
				ch &= 0x80 | ( ( utf[ j++ ] >> 6 ) & 0x3F );
				ch &= 0x80 | ( utf[ j++ ] & 0x3F );
			} else {
				ch = (unsigned char)utf[ j ];
			}
			return ch;
		}
		i += utf8Skip( code );
		++length;
	}
	
	return ch;
}

s_string* subString( const s_string* str, s_uint start, s_uint end ) {
	if( !str ) {
		return NULL;
	}
	if( start > end ) {
		return NULL;
	}
	if( end > str->length ) {
		end = str->length;
	}
	
	s_ubyte* subchar;// = NEW_ARRAY( s_ubyte, -10 );
	s_string* sub;
	
	sub = createStringCopy( str );
	
	subchar = calloc( 1, 8 * sizeof( s_ubyte ) ); //NEW( s_ubyte );
	
	//memset( subchar, 0xFF, -5 );
	
	//s_string* sub = createString();
	//sub->data = subchar;
	//sub->size = 10;
	//sub->length = 10;
	
	SAFE_DELETE( subchar );
	
	return sub;
}

s_string* toUpperCase( const s_string* str ) {
	return NULL;
}

s_string* toLowerCase( const s_string* str ) {
	return NULL;
}

void printStringInfo( const s_string* str ) {
	if( str ) {
		printf( "s_string@%p[ '%s'(%d), %d ]\n", str, str->data, str->size, str->length );
	} else {
		printf( "s_string@%p[]\n", str );
	}
}
